package pl.edu.pw.polygen.ui.explorer;

import java.text.DateFormat;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import pl.edu.pw.polygen.MainWindow;
import pl.edu.pw.polygen.PolygenApplication;
import pl.edu.pw.polygen.beans.FileBean;
import pl.edu.pw.polygen.beans.ProjectBean;
import pl.edu.pw.polygen.core.file.FileService;
import pl.edu.pw.polygen.core.project.ProjectService;
import pl.edu.pw.polygen.exceptions.ProjectNotExistException;
import pl.edu.pw.polygen.ui.file.EditorPanelFactory;
import pl.edu.pw.polygen.ui.file.FilePropertiesWindow;
import pl.edu.pw.polygen.ui.file.FileWindow;
import pl.edu.pw.polygen.ui.project.ProjectPropertiesWindow;
import pl.edu.pw.polygen.util.ApplicationHelper;
import pl.edu.pw.polygen.util.ApplicationHolder;

import com.vaadin.data.Item;
import com.vaadin.event.Action;
import com.vaadin.ui.TreeTable;

//@Component("projectTreeTable")
//@Scope("session")
public class ProjectTreeTableImpl extends TreeTable implements ProjectTreeTable {

	private static final long serialVersionUID = -2687060716183561581L;
	private Logger LOG = Logger.getLogger(ProjectTreeTableImpl.class);
	private ProjectTreeTableImpl instance;
	
	private static final boolean PROJECT_ITEM = true;
	private static final boolean FILE_ITEM = false;

	@Autowired
	private ProjectService projectService;
	
	@Autowired 
	private FileService fileService;
	
	@Autowired
	private EditorPanelFactory editorPanelFactory;
	
	@Autowired
	private FileWindow fileWindow;
	
	@Autowired 
	private ProjectPropertiesWindow projectPropertiesWindow;
	
	@Autowired
	private FilePropertiesWindow filePropertiesWindow;

	private static final Action ACTION_NEW_PROJECT = new Action("New Project");
	private static final Action ACTION_NEW_FILE = new Action("New file");
	private static final Action ACTION_OPEN = new Action("Open");
	private static final Action ACTION_CLOSE = new Action("Close");
	private static final Action ACTION_DELETE = new Action("Delete");
	private static final Action ACTION_PROPERTIES = new Action("Properties");
	private static final Action[] ACTIONS = new Action[] { ACTION_NEW_PROJECT,
			ACTION_NEW_FILE, ACTION_OPEN, ACTION_CLOSE, ACTION_DELETE, ACTION_PROPERTIES };

	protected static final String NAME_PROPERTY = "Name";
	protected static final String MODIFIED_PROPERTY = "Last Modified";

	public ProjectTreeTableImpl() {
		super();
		setSelectable(true);
		
		instance = this;
	}

	@PostConstruct
	private void initialize() {
		setWidth("100%");
		setHeight("100%");
		addContainerProperty(NAME_PROPERTY, String.class, "");
		addContainerProperty(MODIFIED_PROPERTY, String.class, DateFormat
				.getDateInstance().format(new Date()));
		addActionHandler(new ProjectActionHandler());
	}

	@Override
	public void loadProjects() {
		
		List<ProjectBean> projectsList = projectService.getAllUserProjects(ApplicationHelper.getLoggedUser().getUsername());
		for (ProjectBean projectBean : projectsList) {
			try{
				addProjectBean(projectBean);
			}catch(ProjectNotExistException e){
				getWindow().showNotification(e.getMessage());
			}
		}
	}

	class ProjectActionHandler implements Action.Handler {

		private static final long serialVersionUID = -7020815211662446935L;

		@Override
		public Action[] getActions(Object target, Object sender) {
			if (target == null) {
				return new Action[] {ACTION_NEW_PROJECT };
			} else if (instance.areChildrenAllowed(target)) {
				return new Action[] { ACTION_OPEN, ACTION_NEW_FILE,
						ACTION_DELETE, ACTION_PROPERTIES, ACTION_CLOSE };
			} else {
				return new Action[] { ACTION_OPEN, ACTION_DELETE, ACTION_PROPERTIES };
			}
		}

		@Override
		public void handleAction(Action action, Object sender, Object target) {
			if(action == ACTION_OPEN){
				if(areChildrenAllowed(target)==false){
					openFile(target);
				}else{
					openProject(target);
				}
			}else if(action == ACTION_CLOSE){
				closeProject(target);
			}else if(action == ACTION_NEW_FILE){
				createNewFile(target);
			}else if(action == ACTION_DELETE){
				if(areChildrenAllowed(target)==false){
					removeFile(target);
				}else{
					removeProject(target);
				}
			}else if(action == ACTION_PROPERTIES){
				if(areChildrenAllowed(target)==false){
					showFileProperties(target);
				}else{
					showProjectProperties(target);
				}
			}
		}
		
		

		private void openFile(Object target){
			MainWindow mainWindow = (MainWindow) ((PolygenApplication)ApplicationHolder.getApplication()).getMainWindow();
			String fileName = (String) getItem(target).getItemProperty(NAME_PROPERTY).getValue();
			mainWindow.addTab(fileName,editorPanelFactory.getPanel());
		}
		
		private void openProject(Object target){
			setCollapsed(target, false);
		}
		
		
		private void closeProject(Object target){
			setCollapsed(target, true);
		}
		

	}

	@Override
	public void addProjectBean(ProjectBean projectBean) throws ProjectNotExistException {
		Object parentItemId = addItem(new Object[] {
				projectBean.getName(),
				DateFormat.getDateInstance().format(projectBean.getLastModification()) }, null);
		LOG.info(projectBean.getName() + " has been added with id " + parentItemId + " / " + getItemIds().size());
		List<FileBean> fileList = projectBean.getFiles();
		if(fileList!=null){
			for(FileBean fileBean : fileList){
				addFileBean(fileBean);
			}
		}
		requestRepaintAll();
	}

	@Override
	public void addFileBean(FileBean fileBean) throws ProjectNotExistException{
		String projectName = fileBean.getProject().getName();
		Object parentItemId = findByName(projectName,PROJECT_ITEM);
		if(parentItemId == null){
			throw new ProjectNotExistException("Project " + projectName + " could not be find.");
		}
		Object itemId = addItem(new Object[]{
				fileBean.getFileName(), DateFormat.getDateInstance().format(fileBean.getModificationDate()) }, null);
		setParent(itemId, parentItemId);
		setChildrenAllowed(itemId,false);
		requestRepaintAll();
	}
	
	
	@Override
	public void renameProject(String oldName, String newName) {
		Object id = findByName(oldName,PROJECT_ITEM);
		getItem(id).getItemProperty(NAME_PROPERTY).setValue(newName);
	}
	
	@Override
	public void renameFile(String oldProject, String oldFile, String newProject, String newFile) {
		Object projectId = findByName(oldProject,PROJECT_ITEM);
		Object[] childs = getChildren(projectId).toArray();
		if(childs!=null){
			for(Object child : childs){
				Item item = getItem(child);
				String s = (String)item.getItemProperty(NAME_PROPERTY).getValue();
				if(oldFile.equals(s)){
					if(oldProject.equals(newProject)){
						item.getItemProperty(NAME_PROPERTY).setValue(newFile);
					}else{
						Object newProjectId = findByName(newProject,PROJECT_ITEM);
						setParent(child, newProjectId);
					}
				}
			}
		}
	}

	private Object findByName(String name, boolean type){
		Object [] ids = getItemIds().toArray();
		for(Object id : ids){
			Item item = getItem(id);
			String s = (String)item.getItemProperty(NAME_PROPERTY).getValue();
			if(name.equals(s)){
				if(areChildrenAllowed(id)==type){
					return id;
				}
			}
		}
		return null;
	}
	
	private void removeProject(Object target){
		if(hasChildren(target)){
			Object[] childIds = getChildren(target).toArray();
			for(Object id : childIds){
				removeFile(id);
			}
		}
		String projectName = (String)getItem(target).getItemProperty(NAME_PROPERTY).getValue();
		Long userId = ApplicationHelper.getLoggedUser().getId();
		projectService.removeProject(projectName, userId);
		removeItem(target);
	}
	
	private void removeFile(Object target){
		String fileName = (String)getItem(target).getItemProperty(NAME_PROPERTY).getValue();
		Object parentId = getParent(target);
		String projectName = (String)getItem(parentId).getItemProperty(NAME_PROPERTY).getValue();
		Long userId = ApplicationHelper.getLoggedUser().getId();
		fileService.removeFile(fileName,projectName,userId);
		removeItem(target);
	}
	
	private void createNewFile(Object target){
		if (fileWindow.getParent() == null) {
			 fileWindow.init((String)getItem(target).getItemProperty(NAME_PROPERTY).getValue());
			 ApplicationHolder.getApplication().getMainWindow().addWindow(fileWindow);
		}
	}
	
	private void showProjectProperties(Object target) {
		if (projectPropertiesWindow.getParent() == null) {
			 String projectName = (String)getItem(target).getItemProperty(NAME_PROPERTY).getValue();
			 projectPropertiesWindow.initialize(projectName);
			 ApplicationHolder.getApplication().getMainWindow().addWindow(projectPropertiesWindow);
		}
	}

	private void showFileProperties(Object target) {
		if (filePropertiesWindow.getParent() == null) {
			 String fileName = (String)getItem(target).getItemProperty(NAME_PROPERTY).getValue();
			 String projectName = (String)getItem(getParent(target)).getItemProperty(NAME_PROPERTY).getValue();
			 filePropertiesWindow.initialize(fileName,projectName);
			 ApplicationHolder.getApplication().getMainWindow().addWindow(filePropertiesWindow);
		}
		
	}

}
